package main;

import java.util.HashMap;
import java.util.Iterator;
import java.util.Vector;



import nl.uu.cs.treewidth.ngraph.ListGraph;
import nl.uu.cs.treewidth.ngraph.ListVertex;
import nl.uu.cs.treewidth.ngraph.NGraph;
import nl.uu.cs.treewidth.ngraph.NVertex;

import org.jgrapht.graph.DefaultDirectedWeightedGraph;
import org.jgrapht.graph.DefaultWeightedEdge;

import clustering.ClusterWeightedEdge;

import components.Agent;
import components.Operator;

import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.graph.Graph;
import graphNew.AgentEdge;
import graphNew.DinicMainGraph;
import graphNew.FlowingEdge;
import graphNew.MainGraph;


/**
 * 
 * @author dannysi
 *a class with bunch of static functions to translate between all the kinds of graphs we used
 */
public class Translating {
	
	//translates the main graph that we work with into JUNG format graph, for visualization
	public static Graph<Operator, DefaultWeightedEdge> ourGraphToJungGraph(MainGraph graph){
		Graph<Operator, DefaultWeightedEdge> g = new DirectedSparseGraph<Operator, DefaultWeightedEdge>();
		
		try {
			for(Operator vertex : graph.getMainGraph().vertexSet()){
				g.addVertex(vertex);

			}
			
			for(DefaultWeightedEdge edge : graph.getMainGraph().edgeSet()){
				g.addEdge(edge, graph.getMainGraph().getEdgeSource(edge), graph.getMainGraph().getEdgeTarget(edge));
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}			
		
		return g;
	}
	
	//translates the main graph into Dinic Flow graph, with source and sink
	public static DinicMainGraph ourGraphToDinicGraph(MainGraph graph){
		DefaultDirectedWeightedGraph<Operator, FlowingEdge> ddwGraph = new DefaultDirectedWeightedGraph<Operator, FlowingEdge>(FlowingEdge.class);
		
		try {
			for(Operator op : graph.getMainGraph().vertexSet()){
				ddwGraph.addVertex(op);
			}
			for(DefaultWeightedEdge edge : graph.getMainGraph().edgeSet()){
				ddwGraph.addEdge(graph.getMainGraph().getEdgeSource(edge), graph.getMainGraph().getEdgeTarget(edge));
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
		
		DinicMainGraph dinic = new DinicMainGraph(ddwGraph, null, null);
		return dinic;
	}
	
	//helping function for translating Dinic network into JUNG format graph.
	//Is used in dinicNetworkToJungGraph() func.
	public static Graph<Operator, FlowingEdge> ourFlowGraphToJungGraph(DefaultDirectedWeightedGraph graph){
		Graph<Operator, FlowingEdge> g = new DirectedSparseGraph<Operator, FlowingEdge>();
		
		try {
			for(Object vertex : graph.vertexSet()){
				g.addVertex((Operator)vertex);

			}
			
			for(Object edge : graph.edgeSet()){
				g.addEdge((FlowingEdge) edge, (Operator)graph.getEdgeSource(edge), (Operator)graph.getEdgeTarget(edge));
			}
			
		} catch (Exception e) {
			e.printStackTrace();
		}			
		
		return g;
	}
	
	//The opposite to the ourGraphToJungGraph() func.
	//Translates 
	public static MainGraph jungGraphToOurGraph (Graph<Operator, DefaultWeightedEdge> jungGraph){
		Vector<Operator> verteces = new Vector<Operator>();	
		
		for (Operator vertex : jungGraph.getVertices()){
			verteces.add(vertex);
		}
		
		return new MainGraph(verteces);
	}
	
	//translates Dinic flow graph into JUNG format graph, so it'll be able to be visualized.
	//the returned graph has still sink and source
	public static Graph<Operator, FlowingEdge> dinicNetworkToJungGraph(DinicMainGraph dGraph){
		DefaultDirectedWeightedGraph<Operator, FlowingEdge> g = dGraph.getMaingraph();

		return ourFlowGraphToJungGraph(g);
	}
	
	//Translates Agent Graph (the resulting one) into JUNG format for visualization		
	public static Graph<Agent, DefaultWeightedEdge> agentGraphToJungGraph(DefaultDirectedWeightedGraph<Agent, AgentEdge> graph){
		Graph<Agent, DefaultWeightedEdge> jungGraph = new DirectedSparseGraph<Agent, DefaultWeightedEdge>();
		
		for(Agent vertex : graph.vertexSet()){
			jungGraph.addVertex(vertex);
		}
		for(AgentEdge edge : graph.edgeSet()){
			jungGraph.addEdge(edge, graph.getEdgeSource(edge), graph.getEdgeTarget(edge));
		}
		
		return jungGraph;
		
	}
	
	//Translating our main graph into ListGraph.
	//used for tree-width algorithms
	public static  ListGraph<Agent> ourGraphToListGraph(DefaultDirectedWeightedGraph<Agent, AgentEdge> graph){
		ListGraph<Agent> ans= new ListGraph<Agent>();
		HashMap<Agent, ListVertex<Agent>> hash= new HashMap<Agent, ListVertex<Agent>>();
		for (Agent i:graph.vertexSet()){
			ListVertex<Agent> v = new ListVertex<Agent>(i);
			ans.addVertex(v);
			hash.put(i,v);
		}
		for (AgentEdge i:graph.edgeSet())
			ans.addEdge(hash.get(graph.getEdgeSource(i)), hash.get(graph.getEdgeTarget(i)));
		return ans;
	}

	//Translating JUNG format graph into ListGraph.
	//used for tree-width algorithms
	public static ListGraph<Agent> jungGraphToListGraph(Graph<Agent, ClusterWeightedEdge> graph) {
		ListGraph<Agent> ans = new ListGraph<Agent>();
		HashMap<Agent, ListVertex<Agent>> hash= new HashMap<Agent, ListVertex<Agent>>();
		for (Agent i: graph.getVertices()){
			ListVertex<Agent> v = new ListVertex<Agent>(i);
			ans.addVertex(v);
			hash.put(i,v);
		}
		for (ClusterWeightedEdge i: graph.getEdges())
			ans.addEdge(hash.get(graph.getEndpoints(i).getFirst()), hash.get(graph.getEndpoints(i).getSecond()));
		return ans;
	}

}



